package cn.xinfei.xdecision.engine.runner.executor.handler;

import cn.xinfei.xdecision.common.model.component.scorecard.ScorecardDetail;
import cn.xinfei.xdecision.common.model.component.scorecard.ScorecardDimension;
import cn.xinfei.xdecision.common.model.component.scorecard.vo.ScorecardDetailVo;
import cn.xinfei.xdecision.common.model.component.scorecard.vo.ScorecardDimensionVo;
import cn.xinfei.xdecision.common.model.component.scorecard.vo.ScorecardVersionVo;
import cn.xinfei.xdecision.common.utils.util.runner.JevalUtil;
import cn.xinfei.xdecision.common.vo.FieldInfoVo;
import cn.xinfei.xdecision.engine.runner.context.AmmunitionDepot;
import cn.xinfei.xdecision.engine.runner.context.PipelineContextHolder;
import cn.xinfei.xdecision.engine.runner.metadata.MetadataProvider;
import cn.xinfei.xdecision.engine.runner.model.ScoreResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;


@Service
@Slf4j
public class ScorecardNodeHandler {

    @Autowired
    private MetadataProvider metadataProvider;

    public BigDecimal executeDecisionTree(ScorecardVersionVo versionVo) {

        List<ScorecardDetail> hitDetailList = new ArrayList<>(); // 命中的评分字段列表
        List<ScorecardDimensionVo> scorecardDimensions = new ArrayList<>();
        if (versionVo != null) {
            scorecardDimensions = versionVo.getScorecardDimension();
            for (ScorecardDimensionVo scorecardDimensionVo : scorecardDimensions) {
                List<ScorecardDetailVo> scorecardDetailVoList = scorecardDimensionVo.getChildren();
                scorecardHitByDimension(hitDetailList, 0, scorecardDetailVoList);
            }
        }
        //给入参中放入评分卡执行结果
        BigDecimal totalScore = new BigDecimal(0);
        List<ScoreResult> scoreResultDetail = new ArrayList<>();
        for (ScorecardDimension scorecardDimension : scorecardDimensions) {
            BigDecimal dimensionScore = new BigDecimal(0);
            ScoreResult scoreResult = new ScoreResult(scorecardDimension.getDimensionName(), scorecardDimension.getId());
            for (ScorecardDetail scorecardDetail : hitDetailList) {
                if (!scorecardDetail.getDimensionId().equals(scorecardDimension.getId())) {
                    continue;
                }
                String fieldEn = scorecardDetail.getFieldCode();
                Integer scoreCalculateType = versionVo.getScoreCalculateType();
                Integer calculateType = scorecardDetail.getCalculateType();
                // 计算方式为 得分
                if (calculateType == 1) {
                    BigDecimal value = new BigDecimal(scorecardDetail.getScore() + "");
                    if (scoreCalculateType == 1) { // 评分计算方式为 求和
//                        value = new BigDecimal(scorecardDetail.getScore());
                    } else if (scoreCalculateType == 2) { // 评分计算方式为 加权求和
                        value = value.multiply(new BigDecimal(scorecardDimension.getWeight() / 100.00 + ""));
                    }
                    totalScore = totalScore.add(value);
                    dimensionScore = dimensionScore.add(value);
                }
                // 计算方式为 系数
                else if (calculateType == 2) {
//                    String fieldValue = PipelineContextHolder.getValueByKey(fieldEn).toString();
                    Object valueByKeyFromRemote = AmmunitionDepot.getValueByKeyFromRemote(fieldEn);
                    if(null!=valueByKeyFromRemote) {
                        String fieldValue = valueByKeyFromRemote.toString();
                        BigDecimal val = new BigDecimal(fieldValue).multiply(new BigDecimal(scorecardDetail.getCoefficient() + ""));
                        if (scoreCalculateType == 1) { // 评分计算方式为 求和
//                        val = new BigDecimal(fieldValue).multiply(new BigDecimal(scorecardDetail.getCoefficient()));
                        } else if (scoreCalculateType == 2) { // 评分计算方式为 加权求和
//                        val = new BigDecimal(fieldValue).multiply(new BigDecimal(scorecardDetail.getCoefficient()));
                            val = val.multiply(new BigDecimal(scorecardDimension.getWeight() / 100.00 + ""));
                        }
                        totalScore = totalScore.add(val);
                        dimensionScore = dimensionScore.add(val);
                    }
                }
                // 计算方式为 自定义 暂时不支持
                else if (calculateType == 3) {
                    //todo shiyusen
                }
            }
            //最后计算位数
            dimensionScore = dimensionScore.scale() > 20 ? dimensionScore.setScale(20, RoundingMode.HALF_UP) : dimensionScore;
            scoreResult.setScore(dimensionScore);
            scoreResultDetail.add(scoreResult);
        }
        //最后计算位数
        totalScore = totalScore.scale() > 20 ? totalScore.setScale(20, RoundingMode.HALF_UP) : totalScore;
        return totalScore;
    }

    /**
     * 评分卡命中判断
     * 按维度计算同一维度中命中几条规则
     *
     * @param hitDetailList
     * @param detailId
     * @param scorecardDetailVoList
     */
    public void scorecardHitByDimension(List<ScorecardDetail> hitDetailList, Integer detailId, List<ScorecardDetailVo> scorecardDetailVoList) {
        List<ScorecardDetailVo> scorecardDetailVos = scorecardDetailVoList.stream().filter(item -> item.getParentId().equals(detailId)).collect(Collectors.toList());
        for (ScorecardDetailVo scorecardDetailVo : scorecardDetailVos) {

            String condition = scorecardDetailVo.getCondition();
            String fieldCode = scorecardDetailVo.getFieldCode();
            Boolean isHit = isScoreFieldValue(fieldCode, condition);
            Integer dimensionId = scorecardDetailVo.getDimensionId();
            log.info("isHit={},dimensionId={},fieldCode={},condition={},score={}", isHit, dimensionId, fieldCode, condition, scorecardDetailVo.getScore());
            if (isHit) {
                if (scorecardDetailVo.getNodeType() == 1) {
                    //将子节点放入集和中，该子节点包含score
                    log.info("评分卡命中叶子节点,isHit={},dimensionId={},fieldCode={},condition={},score={}", isHit, dimensionId, fieldCode, condition, scorecardDetailVo.getScore());
                    hitDetailList.add(scorecardDetailVo);
                } else {
                    this.scorecardHitByDimension(hitDetailList, scorecardDetailVo.getId(), scorecardDetailVo.getChildren());
                }
            }
        }
    }

    /**
     * 评分卡字段是否在区间内
     *
     * @param fieldCode
     * @param condition
     * @return
     */
    private Boolean isScoreFieldValue(String fieldCode, String condition) {
        if ("(,)".equals(condition)) {
            return true;
        }
        Map<String, Object> param = new HashMap<>();
        ConcurrentMap<String, Object> contextValue = PipelineContextHolder.getContextValue();
        if (contextValue.containsKey(fieldCode)) {
            param.put(fieldCode, contextValue.get(fieldCode));
        } else {
            Map<String, FieldInfoVo> fieldInfo = metadataProvider.getFieldInfo();
            FieldInfoVo fieldInfoVo = fieldInfo.get(fieldCode);
            if(fieldInfoVo==null){
                log.warn("fieldCode is not exists fieldCode={}", fieldCode);
                return false;
            }
            log.info("fieldCode get default={}", fieldInfoVo.getVarDefaultValue());
            param.put(fieldCode, fieldInfoVo.getVarDefaultValue());
        }
        try {
            String exp = JevalUtil.getNumericInterval(condition, fieldCode);
            Boolean aBoolean = JevalUtil.evaluateBoolean(exp, param);
//            log.debug("执行评分卡表达式,exp={},result={}",exp,aBoolean);
            return aBoolean;
        } catch (Exception e) {
            log.error("评分卡变量判断异常，fieldCode={},condition={},fail={}", fieldCode, condition, e.getMessage(), e);
        }
        return false;
    }


}
